﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using AMOOF;

namespace AMOOF {
    class PeriInterface {

        static Boolean scriptRunning = false;
        static Process currentPeriProcess;

        public static string periFolderDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\peri";

        private static void startScript(string script) {
            script += "writeScriptDone(\"" + periFolderDirectory.Replace('\\', '/') + "//" + "PERI_CONTROL.txt\")"; // at end of script, indicate done 
            writeToFile("PERI_OUTPUT.txt", ""); // clear existing file because pari doesn't overwrite it
            writeToFile("AMOOF_RUN_SCRIPT.gp", script);
            writeToFile("PERI_CONTROL.txt", "");
            currentPeriProcess = Process.Start(periFolderDirectory + "\\" + "AMOOF_RUN_SCRIPT.gp");
            scriptRunning = true;
        }

        private static IntegrationRecord readPeriOutput(MultiplePDF pdf) {
            string path2 = periFolderDirectory + "\\" + "PERI_OUTPUT.txt";
            IntegrationRecord thisRecord = new IntegrationRecord();
            try {
                using (StreamReader sr = File.OpenText(path2)) {
                    string s = "";
                    thisRecord.pdf = pdf;
                    iterateToLine("<TOTAL_AREA>", sr);
                    string areaString = sr.ReadLine().Trim();
                    double totalArea = Convert.ToDouble(areaString);
                    thisRecord.totalArea = totalArea;

                    iterateToLine("<BOUNDS>",sr);
                    string boundsString = "";
                    while (!(s = sr.ReadLine()).Trim().Equals("</BOUNDS>")) {
                        boundsString += s.Trim() + "\r\n";
                    }
                    thisRecord.boundsString = boundsString;

                    iterateToLine("<AREA_LEFTCTE_VAR_RIGHTCTE>", sr);
                    while (!(s = sr.ReadLine()).Trim().Equals("</AREA_LEFTCTE_VAR_RIGHTCTE>")) {
                        s.Trim();
                        string[] strings = s.Split(';');
                        double areaAtVar = convertPeriToDouble(strings[0]);
                        double leftCTE = convertPeriToDouble(strings[1]);
                        double VAR = convertPeriToDouble(strings[2]);
                        double rightCTE = convertPeriToDouble(strings[3]); 
                        int percentile = (int)Math.Round(areaAtVar * 100);
                        VarCtePair pair = thisRecord.getPercentile(percentile);
                        pair.integral = areaAtVar;
                        pair.leftCte = leftCTE;
                        pair.var = VAR;
                        pair.rightCte = rightCTE;
                        pair.leftCTEFound = true;
                        pair.rightCTEFound = true;
                    }
                }
            }
            catch (Exception e) {
                Program.log(e.Message + "\r\n" + e.StackTrace);
            }
            return thisRecord;
        }

        private static double convertPeriToDouble(string s) {
            s = s.Trim();
            string[] strings = s.Split(' ');
            if (strings.Count() > 1) {
                string numString = Convert.ToString(strings[0]);
                numString += "e+";
                string powerString = strings[1].Substring(1);
                numString += powerString;
                int power = Convert.ToInt16(powerString);
                if (power > 15) {
                    numString = "" + -1;
                }
                return Convert.ToDouble(numString);
            }
            else {
                return Convert.ToDouble(strings[0]);
            }
        }

        private static void writeToFile(string filename, string text) {
            TextWriter tw = new StreamWriter(periFolderDirectory + "\\" + filename);
            tw.WriteLine(text);
            tw.Close();
        }

        private static void iterateToLine(string value, StreamReader sr) {
            bool done = false;
            while (!done) {
                string line = sr.ReadLine().Trim();
                if (line.Equals(value)) {
                    done = true;
                }
            }
        }

        private static Boolean scriptDone() {
            string path2 = periFolderDirectory + "\\" + "PERI_CONTROL.txt";
            string s = "";
            using (StreamReader sr = File.OpenText(path2)) {
                while ((s = sr.ReadLine()) != null) {
                    s.Trim();
                    if (s.Equals("done")) {
                        currentPeriProcess.Kill();
                        scriptRunning = false;
                    }
                    if (s.Equals("failed")) {
                        currentPeriProcess.Kill();
                        scriptRunning = false;
                        throw new Exception("peri failed to integrate");
                    }
                }
            }
            return !scriptRunning;
        }

        static int allowedSecondsPerPDF = 1000;
        private static void wait() {
            int count = 0;
            while (!scriptDone()) {
                count++;
                if (count > allowedSecondsPerPDF * pdfCount) {
                    currentPeriProcess.Kill();
                    scriptRunning = false;
                    throw new Exception("Peri failed to integrate: Timeout");
                }
                System.Threading.Thread.Sleep(1000);
            }
        }

        private static int pdfCount = 0;
        internal static IntegrationRecord integrate(string script, MultiplePDF pdf) {
            //if (!Directory.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\peri")) {
            //    Directory.CreateDirectory(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\peri");
            //}
            Directory.CreateDirectory(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\peri");
            string fromDirectory = Directory.GetCurrentDirectory() + @"\peri\AMOOF_INTEGRATOR.gp";
            string toDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\peri\AMOOF_INTEGRATOR.gp";
            File.Copy(Directory.GetCurrentDirectory() + @"\peri\AMOOF_INTEGRATOR.gp", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\peri\AMOOF_INTEGRATOR.gp", true);
            startScript(script);
            pdfCount = pdf.pdfs.Count;
            wait();
            IntegrationRecord record = readPeriOutput(pdf);
            return record;
        }
    }
}
